/*
 * Class.c
 *
 *  Created on: 2011-7-8
 *      Author: gexiao
 */

#include "../Dalvik.h"
#include "../../libdex/DexClass.h"

#include <stdlib.h>
#include <stddef.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <assert.h>

/*
 * Class serial numbers start at this value. We use a nonzero initial
 * value so they stand out in binary dumps(e.g. hprof output).
 */
#define INITIAL_CLASS_SERIAL_NUMBER 0x50000000

/*
 * Constant used to size an auxillary class object data structure.
 * For optimum memory use this should be equal to or slightly larger than
 * the number of classes loaded when the zygote finishes initializing.
 */
#define ZYGOTE_CLASS_CUTOFF 2304

#define CLASS_SFIELD_SLOTS 1

static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap);
static ClassObject* findClassFromLoaderNoInit(const char* descriptor,
		Object* loader);
static ClassObject* findClassNoInit(const char* descriptor, Object* loader,
		DvmDex* pDvmDex);
static ClassObject* loadClassFromDex(DvmDex* pDvmDex,
		const DexClassDef* pClassDef, Object* loader);
static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod,
		Method* meth);
static int computeJniArgInfo(const DexProto* proto);
static void loadSFieldFromDex(ClassObject* clazz, const DexField* pDexSField,
		StaticField* sfield);
static void loadIFieldFromDex(ClassObject* clazz, const DexField* pDexIField,
		InstField* field);
static bool createVtable(ClassObject* clazz);
static bool createIftable(ClassObject* clazz);
static bool insertMethodStubs(ClassObject* clazz);
static bool computeFieldOffsets(ClassObject* clazz);
static void throwEarlierClassFailure(ClassObject* clazz);

static size_t classObjectSize(size_t sfieldCount) {
	size_t size;

	size = offsetof(ClassObject, sfields);
	size += sizeof(StaticField) * sfieldCount;
	return size;
}

/*
 * Intialize the bootstrap class loader.
 *
 * Call this after the bootclasspath string has been finalized
 */bool dvmClassStartup(void) {
	//make this a requirement -- don't currently support dirs in path
	if (strcmp(gDvm.bootClassPathStr, ".") == 0) {
		//LOGE("ERROR: must specify non-'.' bootclasspath\n");
		return false;
	}

	gDvm.loadedClasses = dvmHashTableCreate(256,
			(HashFreeFunc) dvmFreeClassInnards);

	gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);
	if (gDvm.pBootLoaderAlloc == NULL)
		return false;

	if (false) {
		//some code here
	}

	/*
	 * Class serial number.  We start with a high value to make it distinct
	 * in binary dumps (e.g. hprof).
	 */
	gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;

	/* Set up the table we'll use for tracking initiating loaders for
	 * early classes.
	 * If it's NULL, we just fall back to the InitiatingLoaderList in the
	 * ClassObject, so it's not fatal to fail this allocation.
	 */
	gDvm.initiatingLoaderList = calloc(ZYGOTE_CLASS_CUTOFF,
			sizeof(InitiatingLoaderList));

	gDvm.classJavaLangClass = (ClassObject*) dvmMalloc(
			classObjectSize(CLASS_SFIELD_SLOTS), ALLOC_DEFAULT);
	DVM_OBJECT_INIT(&gDvm.classJavaLangClass->obj, gDvm.classJavaLangClass);
	gDvm.classJavaLangClass->descriptor = "Ljava/lang/Class;";

	/*
	 * Process the bootstrap class path. This means opening the specified
	 * DEX or Jar files and possibly running them through the optimizer.
	 */assert(gDvm.bootClassPath == NULL);
	processClassPath(gDvm.bootClassPathStr, true);

	if (gDvm.bootClassPath == NULL)
		return false;

	return true;
}

/*
 * ============================================================
 * 		Bootstrap class loader
 * ============================================================
 */

/*
 * Prepare a ClassPathEntry struct, which at this point only has a valid
 * filename. We need to figure out what kind of file it is, and for
 * everything other than directories we need to open it up and see
 * what's inside.
 */
static bool prepareCpe(ClassPathEntry* cpe, bool isBootstrap) {
	JarFile* pJarFile = NULL;
	RawDexFile* pRawDexFile = NULL;
	struct stat sb;
	int cc;

	cc = stat(cpe->filename, &sb);

	if (cc < 0) {
		//LOGD("Unable to stat classpath element '%s'\n", cpe->fileName);
		return false;
	}

	if (S_ISDIR(sb.st_mode)) {
		/*
		 * The directory will usually have .class files in subdirectories,
		 * which may be a few levels down.  Doing a recursive scan and
		 * caching the results would help us avoid hitting the filesystem
		 * on misses.  Whether or not this is of measureable benefit
		 * depends on a number of factors, but most likely it is not
		 * worth the effort (especially since most of our stuff will be
		 * in DEX or JAR).
		 */
		cpe->kind = kCpeDir;
		assert(cpe->ptr == NULL);
		return true;
	}

	if (dvmJarFileOpen(cpe->filename, &pJarFile, isBootstrap) == 0) {
		cpe->kind = kCpeJar;
		cpe->ptr = pJarFile;
		return true;
	}

	//TODO: do we still want to support "raw" DEX files in the classpath?
	if (dvmRawDexFileOpen(cpe->filename, &pRawDexFile, isBootstrap) == 0) {
		cpe->kind = kCpeDex;
		cpe->ptr = pRawDexFile;
		return true;
	}

	//LOGD("Unable to process classpath element '%s'\n", cpe->fileName);
	return false;
}

/*
 * Convert a colon-separated list of directories, Zip files, and DEX file
 * into an array of ClassPathEntry structs.
 *
 * If we're unable to load a bootstrap class path entry,we fail. This is necessary
 * to preserve the dependencies implied by optimized DEX files
 * (e.g. if the same class appears in multiple places).
 *
 * ...
 */
static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap) {
	ClassPathEntry* cpe = NULL;
	char* mangle;
	char* cp;
	const char* end;
	int idx, count;

	mangle = strdup(pathStr);

	count = 1;
	for (cp = mangle; *cp != '\0'; cp++) {
		if (*cp == ':') {
			count++;
			*cp = '\0';
		}
	}
	end = cp;

	/*
	 * Allocate storage. We over-alloc by one so we can set an "end" marker.
	 */
	cpe = (ClassPathEntry*) calloc(count + 1, sizeof(ClassPathEntry));

	/*
	 * Set the global pointer so the DEX file dependency stuff can find it.
	 */
	gDvm.bootClassPath = cpe;

	/*
	 * Go through a second time, pulling stuff out.
	 */
	cp = mangle;
	idx = 0;
	while (cp < end) {
		if (*cp == '\0') {
		} else {
			if (isBootstrap && dvmPathToAbsolutePortion(cp) == NULL) {
				//LOGE("Non-absolute bootclasspath entry '%s'\n", cp);
				free(cpe);
				cpe = NULL;
				goto bail;
			}

			ClassPathEntry tmp;
			tmp.kind = kCpeUnknown;
			tmp.filename = strdup(cp);
			tmp.ptr = NULL;

			//drop an end marker here so DEX loader can walk unfinished list
			cpe[idx].kind = kCpeLastEntry;
			cpe[idx].filename = NULL;
			cpe[idx].ptr = NULL;

			if (!prepareCpe(&tmp, isBootstrap)) {
				free(tmp.filename);
			} else {
				//copy over,pointers and all
				cpe[idx] = tmp;
				idx++;
			}
		}
		cp += strlen(cp) + 1;
	}
	if (idx == 0 && !gDvm.optimizing) {
		//LOGE("No valid entries found in bootclasspath '%s'\n", pathStr);
		free(cpe);
		cpe = NULL;
		goto bail;
	}

	//LOGVV("  (filled %d of %d slots)\n", idx, count);

	//put end marker in over-alloc slot
	cpe[idx].kind = kCpeLastEntry;
	cpe[idx].filename = NULL;
	cpe[idx].ptr = NULL;
	bail: free(mangle);
	gDvm.bootClassPath = cpe;
	return cpe;
}

/*
 * Search the DEX files we loaded from the bootstrap class path for a DEX
 * file that has the class with the matching descriptor.
 *
 * Returns the matching DEX file and DexClassDef entry if found, otherwise
 * returns NULL.
 */
static DvmDex* searchBootPathForClass(const char* descriptor,
		const DexClassDef** ppClassDef) {
	const ClassPathEntry* cpe = gDvm.bootClassPath;
	const DexClassDef* pFoundDef = NULL;
	DvmDex* pFoundFile = NULL;

	while (cpe->kind != kCpeLastEntry) {
		switch (cpe->kind) {
		case kCpeDir:
			break;
		case kCpeJar: {
			JarFile* pJarFile = (JarFile*) cpe->ptr;
			const DexClassDef* pClassDef;
			DvmDex* pDvmDex;

			pDvmDex = dvmGetJarFileDex(pJarFile);
			pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
			if (pClassDef != NULL) {
				//found
				pFoundDef = pClassDef;
				pFoundFile = pDvmDex;
				goto found;
			}
		}
			break;
		case kCpeDex: {
			RawDexFile* pRawDexFile = (RawDexFile*) cpe->ptr;
			const DexClassDef* pClassDef;
			DvmDex* pDvmDex;

			pDvmDex = dvmGetRawDexFileDex(pRawDexFile);
			pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
			if (pClassDef != NULL) {
				/* found */
				pFoundDef = pClassDef;
				pFoundFile = pDvmDex;
				goto found;
			}
		}
			break;
		default:
			break;
		}
		cpe++;
	}

	/*
	 * Special handling during verification + optimization.
	 *
	 * The DEX optimizer needs to load classes from the DEX file it's working
	 * on. Rather than trying to insert it into the bootstrap class path
	 * or synthesizing a class loader to manage it, we just make it available
	 * here. It logically comes after all existing entries in the bootstrap
	 * class path.
	 */
	if (gDvm.bootClassPathOptExtra != NULL) {
		const DexClassDef* pClassDef;

		pClassDef = dexFindClass(gDvm.bootClassPathOptExtra->pDexFile,
				descriptor);
		if (pClassDef != NULL) {
			//found
			pFoundDef = pClassDef;
			pFoundFile = gDvm.bootClassPathOptExtra;
		}
	}

	found: *ppClassDef = pFoundDef;
	return pFoundFile;
}

/*
 * ===============================================
 * 		Class list management
 * ===============================================
 */

//search for these criteria in the Class hash table.
typedef struct ClassMatchCriteria {
	const char* descriptor;
	Object* loader;
} ClassMatchCriteria;

static InitiatingLoaderList *dvmGetInitiatingLoaderList(ClassObject* clazz) {

}

/*
 * Determine if "loader" appears in clazz' initiating loader list.
 *
 * The class hash table lock must be held when calling here, since
 * it's also used when updating a class' initiating loader list.
 */bool dvmLoaderInInitiatingList(const ClassObject* clazz, const Object* loader) {
	/*
	 * The bootstrap class loader can't be just an initiating loader for
	 * anything (it's always the defining loader if the class is visible
	 * to it).  We don't put defining loaders in the initiating list.
	 */
	if (loader == NULL)
		return false;

	/*
	 * Scan the list for a match.  The list is expected to be short.
	 */
	/* Cast to remove the const from clazz, but use const loaderList */
	ClassObject* nonConstClazz = (ClassObject*) clazz;
	const InitiatingLoaderList *loaderList = dvmGetInitiatingLoaderList(
			nonConstClazz);
	int i;
	for (i = loaderList->initiatingLoaderCount - 1; i >= 0; --i) {
		if (loaderList->initiatingLoaders[i] == loader) {
			//LOGI("+++ found initiating match %p in %s\n",
			//    loader, clazz->descriptor);
			return true;
		}
	}
	return false;
}

/*
 * (This is a dvmHashTableLookup callback.)
 *
 * Entries in the class hash table are stored as {descriptor, d-loader}
 * tuples. If the hashed class descriptor matches the requested descriptor,
 * and the hashed defining class loader matches the requested class
 * loader, we're good. If only the descriptor matches, we check to see if the
 * loader is in the hashed class' initiating loader list. If so, we
 * can return "true" immediately and skip some of the loadClass melodrama.
 *
 * The caller must lock the hash table before calling here.
 *
 * Returns 0 if a matching entry is found,nonzero otherwise.
 */
static int hashcmpClassByCrit(const void* vclazz, const void* vcrit) {
	const ClassObject* clazz = (const ClassObject*) vclazz;
	const ClassMatchCriteria* pCrit = (const ClassMatchCriteria*) vcrit;
	bool match;

	match = (strcmp(clazz->descriptor, pCrit->descriptor) == 0
			&& (clazz->classLoader == pCrit->loader || (pCrit->loader != NULL
					&& dvmLoaderInInitiatingList(clazz, pCrit->loader))));

	return !match;
}

/*
 * Like hashcmpClassByCrit, but passing in a fully-formed ClassObject
 * instead of a ClassMatchCriteria.
 */
static int hashcmpClassByClass(const void* vclazz, const void* vaddclazz) {
	const ClassObject* clazz = (const ClassObject*) vclazz;
	const ClassObject* addClazz = (const ClassObject*) vaddclazz;
	bool match;

	match = (strcmp(clazz->descriptor, addClazz->descriptor) == 0
			&& (clazz->classLoader == addClazz->classLoader
					|| (addClazz->classLoader != NULL
							&& dvmLoaderInInitiatingList(clazz,
									addClazz->classLoader))));

	return !match;
}

/*
 * Search through the hash table to find an entry with a matching descriptor
 * and an initiating class loader that matches "loader".
 *
 * The table entries are hashed on descriptor only, because they're unique
 * on *defining* class loader, not *initiating* class loader. This isn't
 * great, because it guarantees we will have to probe when multiple
 * class loaders are used.
 */
ClassObject* dvmLookupClass(const char* descriptor, Object* loader,
		bool unprepOkay) {
	ClassMatchCriteria crit;
	void* found;
	u4 hash;

	crit.descriptor = descriptor;
	crit.loader = loader;

	hash = dvmComputeUtf8Hash(descriptor);

	dvmHashTableLock(gDvm.loadedClasses);
	found = dvmHashTableLookup(gDvm.loadedClasses, hash, &crit,
			hashcmpClassByCrit, false);
	dvmHashTableUnlock(gDvm.loadedClasses);

	/*
	 * The class has been added to the hash table but isn't ready for use.
	 * We're going to act like we didn't see it, so that the caller will
	 * go through the full "find class" path, which includes locking the
	 * object and waiting until it's ready. We could do that lock/wait
	 * here, but this is an extremely rare case, and it's simpler to have
	 * the wait-for-class code centralized.
	 */
	if (found != NULL && !unprepOkay && !dvmIsClassLinked(found)) {
		found = NULL;
	}

	return (ClassObject*) found;
}

/*
 * Add a new class to the hash table.
 *
 * The class is considered "new" if it doesn't match on both the class
 * descriptor and the defining class loader.
 *
 * TODO: we should probably have separate hash tables for each
 * ClassLoader. This could speed up dvmLookupClass and
 * other common operations. It does imply a VM-visible data structure
 * for each ClassLoader object with loaded classes, which we don't
 * have yet.
 */bool dvmAddClassToHash(ClassObject* clazz) {
	void* found;
	u4 hash;

	hash = dvmComputeUtf8Hash(clazz->descriptor);

	dvmHashTableLock(gDvm.loadedClasses);
	found = dvmHashTableLookup(gDvm.loadedClasses, hash, clazz,
			hashcmpClassByClass, true);
	dvmHashTableUnlock(gDvm.loadedClasses);

	//can happen if two threads load the same class simultaneously
	return (found == (void*) clazz);
}

/*
 * Remove a class object from the hash table.
 */
static void removeClassFromHash(ClassObject* clazz) {
	u4 hash = dvmComputeUtf8Hash(clazz->descriptor);

	dvmHashTableLock(gDvm.loadedClasses);
	if (!dvmHashTableRemove(gDvm.loadedClasses, hash, clazz)) {
		//print some information.
	}
	dvmHashTableUnlock(gDvm.loadedClasses);
}
/*
 * ======================================================
 * 		Class creation
 * ======================================================
 */

/*
 * Find the named class (by descriptor), using the specified
 * initiating ClassLoader.
 *
 * The class will be loaded if it has not already been, as will its
 * superclass. It will not be initialized.
 *
 * If the class can't be found, returns NULL with an appropriate exception
 * raised.
 */
ClassObject* dvmFindClassNoInit(const char* descriptor, Object* loader) {
	assert(descriptor != NULL);

	if (*descriptor == '[') {

	} else {
		/*
		 * Regular class. Find in table, generate if not found.
		 */
		if (loader != NULL) {
			return findClassFromLoaderNoInit(descriptor, loader);
		} else {
			return dvmFindSystemClassNoInit(descriptor);
		}
	}
}

/*
 * Load the named class (by descriptor) from the specified class
 * loader. This calls out to let the ClassLoader object do its thing.
 *
 * Returns with NULL and an exception raised on error.
 */
static ClassObject* findClassFromLoaderNoInit(const char* descriptor,
		Object* loader) {

}

/*
 *
 */
ClassObject* dvmFindSystemClass(const char* descriptor) {

}

/*
 * Find the named class (by descriptor), searching for it in the
 * bootclasspath.
 *
 * On failure, this returns NULL with an exception raised.
 */
ClassObject* dvmFindSystemClassNoInit(const char* descriptor) {
	return findClassNoInit(descriptor, NULL, NULL);
}

/*
 * Find the named class (by descriptor). If it's not already loaded,
 * we load it and link it, but don't execute <clinit>. (The VM has
 * specific limitations on which events can cause initialization.)
 *
 * If "pDexFile" is NULL, we will search the bootclasspath for an entry.
 *
 * On failure, this returns NULL with an exception raised.
 *
 * TODO: we need to return an indication of whether we loaded the class or
 * used an existing definition. If somebody deliberately tries to load a
 * class twice in the same class loader, they should get a LinkageError,
 * but inadvertent simultaneous class references should "just work".
 */
static ClassObject* findClassNoInit(const char* descriptor, Object* loader,
		DvmDex* pDvmDex) {
	Thread* self = dvmThreadSelf();
	ClassObject* clazz;

	//some code maybe here

	if (loader != NULL) {
		//printf some information.
	}

	/*
	 * ...
	 */
	if (dvmCheckException(self)) {
		dvmDumpAllThreads(false);
		dvmAbort();
	}

	clazz = dvmLookupClass(descriptor, loader, true);

	if (clazz == NULL) {
		const DexClassDef* pClassDef;
		//may have some code here
		if (pDvmDex == NULL) {
			assert(loader == NULL); //shouldn't be here otherwise
			pDvmDex = searchBootPathForClass(descriptor, &pClassDef);
		} else {
			pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
		}

		if (pDvmDex == NULL || pClassDef == NULL) {
			dvmThrowExceptionWithClassMessage(
					"Ljava/lang/NoClassDefFoundError;", descriptor);
			goto bail;
		}

		//found a match, try to load it
		clazz = loadClassFromDex(pDvmDex, pClassDef, loader);
		if (dvmCheckException(self)) {
			//class was found but had issues
			dvmReleaseTrackedAlloc((Object*) clazz, NULL);
			goto bail;
		}

		/*
		 * Lock the class while we link it so other threads must wait for us
		 * to finish. Set the "initThreadId" so we can identify recursive
		 * invocation.
		 */
		dvmLockObject(self, (Object*) clazz);
		clazz->initThreadId = self->threadId;

		/*
		 * Add to hash table to lookups succeed.
		 *
		 * [Are circular references possible when linking a class?]
		 */assert(clazz->classLoader == loader);
		if (!dvmAddClassToHash(clazz)) {
			/*
			 * Another thread must have loaded the class after we
			 * started but before we finished. Discard what we've
			 * done and leave some hints for the GC.
			 *
			 * (Yes, this happens.).
			 */
			clazz->initThreadId = 0;
			dvmUnlockObject(self, (Object*) clazz);

			/*
			 * Let the GC free the class.
			 */assert(clazz->obj.clazz==gDvm.unlinkedJavaLangClass);
			dvmReleaseTrackedAlloc((Object*) clazz, NULL);

			/*
			 * Grab the winning class.
			 */
			clazz = dvmLookupClass(descriptor, loader, true);
			assert(clazz!=NULL);
			goto got_class;
		}
		dvmReleaseTrackedAlloc((Object*) clazz, NULL);
		//may have some code here.

		/*
		 * Prepare and resolve.
		 */
		if (!dvmLinkClass(clazz, false)) {
			assert(dvmCheckException(self));

			/*
			 * Make note of the error and clean up the class.
			 */
			removeClassFromHash(clazz);
			clazz->status = CLASS_ERROR;
			dvmFreeClassInnards(clazz);

			/*
			 * Let any waiters know.
			 */
			clazz->initThreadId = 0;
			dvmObjectNotifyAll(self, (Object*) clazz);
			dvmUnlockObject(self, (Object*) clazz);

			clazz = NULL;
			if (gDvm.optimizing) {
				//happens with "external" libs
				//print some information
			} else {
				//print some information
			}
			goto bail;
		}
		dvmObjectNotifyAll(self, (Object*) clazz);
		dvmUnlockObject(self, (Object*) clazz);

		/*
		 * Add class stats to global counters.
		 *
		 * TODO: these should probably be atomic ops.
		 */
		gDvm.numLoadedClasses++;
		gDvm.numDeclaredMethods += clazz->virtualMethodCount
				+ clazz->directMethodCount;
		gDvm.numDeclaredInstFields += clazz->ifieldCount;
		gDvm.numDeclaredStaticFields += clazz->sfieldCount;

		/*
		 * Cache pointers to basic classes. We want to use these in
		 * various places, and it's easiest to initialize them on first
		 * use rather than trying to force them to initialize(startup
		 * ordering makes it weird).
		 */
		if (gDvm.classJavaLangObject == NULL && strcmp(descriptor,
				"Ljava/lang/Object;") == 0) {
			/*
			 * It should be impossible to get here with anything
			 * bue the bootclasspath loader.
			 */assert(loader==NULL);
			gDvm.classJavaLangObject = clazz;
		}
	} else {
		got_class: if (!dvmIsClassLinked(clazz) && clazz->status != CLASS_ERROR) {
			/*
			 * We can race with other threads for class linking. We should
			 * never get here recursively; doing so indicates that two
			 * classes have circular dependencies.
			 *
			 * One exception: we force discovery of java.lang.Class in
			 * dvmLinkClass(), and Class has Object as its superclass. So
			 * if the first thing we ever load is Object, we will init
			 * Object->Class->Object. The easiest way to avoid this is to
			 * ensure that Object is never the first thing we look up, so
			 * we get Foo->Class->Object instead.
			 */
			dvmLockObject(self, (Object*) clazz);
			if (!dvmIsClassLinked(clazz) && clazz->initThreadId
					== self->threadId) {
				dvmUnlockObject(self, (Object*) clazz);
				dvmThrowExceptionWithClassMessage(
						"Ljava/lang/ClassCircularityError;", clazz->descriptor);
				clazz = NULL;
				goto bail;
			}

			while (!dvmIsClassLinked(clazz) && clazz->status != CLASS_ERROR) {
				//dvmObjectWait(self, (Object*) clazz, 0, 0, false);
			}
			dvmUnlockObject(self, (Object*) clazz);
		}

		if (clazz->status == CLASS_ERROR) {
			/*
			 * Somebody else tried to load this and failed. We need to raise
			 * an exception and report failure.
			 */
			throwEarlierClassFailure(clazz);
			clazz = NULL;
			goto bail;
		}
	}

	//check some invariants
	assert(dvmIsClassLinked(clazz));
	assert(gDvm.classJavaLangClass != NULL);
	assert(clazz->obj.clazz == gDvm.classJavaLangClass);

	if (clazz != gDvm.classJavaLangObject) {
		assert(clazz->super!=NULL);
	}
	if (!dvmIsInterfaceClass(clazz)) {
		assert(clazz->vtableCount >= clazz->virtualMethodCount);
	}

	/*
	 * Normally class objects are initialized before we instantiate them,
	 * but we can't do that with java.lang.Class (chichen,meet egg). We
	 * do it explicitly here.
	 *
	 * The verifier could call here to find Class while verifying Class,
	 * so we need to check for CLASS_VERIFYING as well as !initialized.
	 */
	if (clazz == gDvm.classJavaLangClass && !dvmIsClassInitialized(clazz)
			&& !(clazz->status == CLASS_VERIFYING)) {
		dvmInitClass(clazz);
	}
	bail: assert(clazz!=NULL||dvmCheckException(self));
	return clazz;
}

/*
 * Helper for loadClassFromDex, which takes a DexClassDataHeader and
 * encoded data pointer in addition to the other arguments.
 */
static ClassObject* loadClassFromDex0(DvmDex* pDvmDex,
		const DexClassDef* pClassDef, const DexClassDataHeader* pHeader,
		const u1* pEncodedData, Object* classLoader) {
	ClassObject* newClass = NULL;
	const DexFile* pDexFile;
	const char* descriptor;
	int i;

	pDexFile = pDvmDex->pDexFile;
	descriptor = dexGetClassDescriptor(pDexFile, pClassDef);

	//some code here

	/*
	 * Allocate storage for the class object on the GC heap, so that other
	 * objects can have references to it. We bypass the usual mechanism
	 * (allocObject), because we don't have all the bits and pieces yet.
	 *
	 * Note that we assume that java.lang.Class does not override
	 * finalize().
	 */
	newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
	if (newClass == NULL)
		return NULL;

	/*
	 * Until the class is loaded and linked, use a placeholder
	 * obj->clazz value as a hint to the GC. We don't want
	 * the GC trying to scan the object while it's full of Idx
	 * values. Also, the real java.lang.Class may not exist
	 * yet.
	 */DVM_OBJECT_INIT(&newClass->obj,gDvm.unlinkedJavaLangClass);

	newClass->descriptor = descriptor;
	assert(newClass->descriptorAlloc == NULL);
	newClass->accessFlags = pClassDef->accessFlags;
	newClass->classLoader = classLoader;
	newClass->pDvmDex = pDvmDex;
	newClass->primitiveType = PRIM_NOT;

	/*
	 * Stuff the superclass index into the object pointer field. The linker
	 * pulls it out and replaces it with a resolved ClassObject pointer.
	 * I'm doing it this way (rather than having a dedicated superclassIdx
	 * field) to save a few bytes of overhead per class.
	 *
	 * newClass->super is not traversed or freed by dvmFreeClassInnards, so
	 * this is safe.
	 */assert(sizeof(u4) == sizeof(ClassObject*));
	newClass->super = (ClassObject*) pClassDef->superclassIdx;

	/*
	 * Stuff class reference indices into the pointer fields.
	 *
	 * The elements of newClass->interfaces are not traversed or freed by
	 * dvmFreeClassInnards, so this is GC-safe.
	 */
	const DexTypeList* pInterfacesList;
	pInterfacesList = dexGetInterfacesList(pDexFile, pClassDef);
	if (pInterfacesList != NULL) {
		newClass->interfaceCount = pInterfacesList->size;
		newClass->interfaces = (ClassObject**) dvmLinearAlloc(classLoader,
				newClass->interfaceCount * sizeof(ClassObject*));

		for (i = 0; i < newClass->interfaceCount; i++) {
			const DexTypeItem* pType = dexGetTypeItem(pInterfacesList, i);
			newClass->interfaces[i] = (ClassObject*) (u4) pType->typeIdx;
		}
		dvmLinearReadOnly(classLoader, newClass->interfaces);
	}

	//load field definitions

	/*
	 * TODO: consider over-allocating the class object and appending the
	 * static field info onto the end. It's fixed-size and known at alloc
	 * time. This would save a couple of native heap allocations, but it
	 * would also make heap compaction more difficult because we pass Field
	 * pointers around internally.
	 */
	if (pHeader->staticFieldsSize != 0) {
		//static fields stay on system heap; field data isn't "write once"
		int count = (int) pHeader->staticFieldsSize;
		u4 lastIndex = 0;
		DexField field;

		newClass->sfieldCount = count;
		newClass->sfields = (StaticField*) calloc(count, sizeof(StaticField));
		for (i = 0; i < count; i++) {
			dexReadClassDataField(&pEncodedData, &field, &lastIndex);
			loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
		}
	}

	if (pHeader->instanceFieldsSize != 0) {
		int count = (int) pHeader->instanceFieldsSize;
		u4 lastIndex = 0;
		DexField field;

		newClass->ifieldCount = count;
		newClass->ifields = (InstField*) dvmLinearAlloc(classLoader,
				count * sizeof(InstField));
		for (i = 0; i < count; i++) {
			dexReadClassDataField(&pEncodedData, &field, &lastIndex);
			loadIFieldFromDex(newClass, &field, &newClass->ifields[i]);
		}
		dvmLinearReadOnly(classLoader, newClass->ifields);
	}

	//load method definitions
	if (pHeader->directMethodsSize != 0) {
		int count = (int) pHeader->directMethodsSize;
		u4 lastIndex = 0;
		DexMethod method;

		newClass->directMethodCount = count;
		newClass->directMethods = (Method*) dvmLinearAlloc(classLoader,
				count * sizeof(Method));
		for (i = 0; i < count; i++) {
			dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
			loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
		}
		dvmLinearReadOnly(classLoader, newClass->directMethods);
	}

	if (pHeader->virtualMethodsSize != 0) {
		int count = (int) pHeader->virtualMethodsSize;
		u4 lastIndex = 0;
		DexMethod method;

		newClass->virtualMethodCount = count;
		newClass->virtualMethods = (Method*) dvmLinearAlloc(classLoader,
				count * sizeof(Method));
		for (i = 0; i < count; i++) {
			dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
			loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
		}
		dvmLinearReadOnly(classLoader, newClass->virtualMethods);
	}

	newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);
	newClass->status = CLASS_LOADED;

	//caller must call dvmReleaseTrackedAlloc
	return newClass;
}

/*
 * Try to load the indicated class from the specified DEX file.
 *
 * This is effectively loadClass()+defineClass() for a DexClassDef.
 * loading was largely done when we crunched through the DEX.
 *
 * Returns NULL on failure. If we locate the class but encounter an error
 * while processing it, an appropriate exception is thrown.
 */
static ClassObject* loadClassFromDex(DvmDex* pDvmDex,
		const DexClassDef* pClassDef, Object* classLoader) {
	ClassObject* result;
	DexClassDataHeader header;
	const u1* pEncodedData;
	const DexFile* pDexFile;

	assert((pDvmDex != NULL) && (pClassDef != NULL));
	pDexFile = pDvmDex->pDexFile;

	//some code here

	pEncodedData = dexGetClassData(pDexFile, pClassDef);

	if (pEncodedData != NULL) {
		dexReadClassDataHeader(&pEncodedData, &header);
	} else {
		memset(&header,0,sizeof(header));
	}

	result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData,
			classLoader);

	//some code here.

	return result;
}

/*
 * Clone a Method, making new copies of anything that will be freed up
 * by freeMethodsInnards().
 */
static void cloneMethod(Method* dst, const Method* src) {
	memcpy(dst,src,sizeof(Method));
}

/*
 * Pull the interesting pieces out of a DexMethod.
 *
 * The DEX file isn't going anywhere, so we don't need to make copies of
 * the code area.
 */
static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod,
		Method* meth) {
	DexFile* pDexFile = clazz->pDvmDex->pDexFile;
	const DexMethodId* pMethodId;
	const DexCode* pDexCode;

	pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);

	meth->name = dexStringById(pDexFile, pMethodId->nameIdx);
	dexProtoSetFromMethodId(&meth->prototype, pDexFile, pMethodId);
	meth->shorty = dexProtoGetShorty(&meth->prototype);
	meth->accessFlags = pDexMethod->accessFlags;
	meth->clazz = clazz;
	meth->jniArgInfo = 0;

	if (dvmCompareNameDescriptorAndMethod("finalize", "()V", meth) == 0) {
		SET_CLASS_FLAG(clazz,CLASS_ISFINALIZABLE);
	}
	pDexCode = dexGetCode(pDexFile, pDexMethod);
	if (pDexCode != NULL) {
		//integer constants,copy over for faster access
		meth->registersSize = pDexCode->registerSize;
		meth->insSize = pDexCode->insSize;
		meth->outsSize = pDexCode->outsSize;

		//pointer to code area
		meth->insns = pDexCode->insns;
	} else {
		/*
		 * We don't have a DexCode block, but we still want to know how
		 * much space is needed for the arguments (so we don't have to
		 * compute it later). We also take this opportunity to compute
		 * JNI argument info.
		 *
		 * We do this for abstract methods as well, because we want to
		 * be able to substitute our exception-throwing "stub" in.
		 */
		int argsSize = dvmComputeMethodArgsSize(meth);
		if (!dvmIsStaticMethod(meth))
			argsSize++;
		meth->registersSize = meth->insSize = argsSize;
		assert(meth->outsSize == 0);
		assert(meth->insns == NULL);

		if (dvmIsNativeMethod(meth)) {
			meth->nativeFunc = dvmResolveNativeMethod;
			meth->jniArgInfo = computeJniArgInfo(&meth->prototype);
		}
	}

}

/*
 * jniArgInfo (32-bit int) layout:
 * 	 SRRRLLLL FFFFFFFF FFFFFFFF FFFFFFFF
 *
 * 	 S - if set, do things the hard way (scan the signature)
 * 	 R - return-type enumeration
 * 	 L - number of double-words of storage required on stack (0-30 words)
 * 	 F - pad flag -- if set, write a pad word to the stack before copying
 * 	 	 the next 32 bits
 *
 * With this arrangement we can push up to 24 words of arguments without
 * having to scan the signature. Only works for ABIs that don't require
 * special handling of floating-point args (e.g. ARM can make use of it,
 * PPC can't).
 *
 * The return-type bits are always set, even if we have too many args to
 * set the L/F bits. This allows us to avoid scanning through the signature
 * for the return type on all platforms.
 */
static int computeJniArgInfo(const DexProto* proto) {
	const char* sig = dexProtoGetShorty(proto);
	int returnType, padFlags, jniArgInfo;
	char sigByte;
	int stackOffset, padMask;

	stackOffset = padFlags = 0;
	padMask = 0x00000001;

	//The first shorty character is the return type.
	switch (*(sig++)) {
	case 'V':
		returnType = DALVIK_JNI_RETURN_VOID;
		break;
	case 'F':
		returnType = DALVIK_JNI_RETURN_FLOAT;
		break;
	case 'D':
		returnType = DALVIK_JNI_RETURN_DOUBLE;
		break;
	case 'J':
		returnType = DALVIK_JNI_RETURN_S8;
		break;
	default:
		returnType = DALVIK_JNI_RETURN_S4;
		break;
	}

	while (true) {
		sigByte = *(sig++);

		if (sigByte == '\0')
			break;

		if (sigByte == 'D' || sigByte == 'J') {
			if ((stackOffset & 1) != 0) {
				padFlags |= padMask;
				stackOffset++;
				padMask <<= 1;
			}
			stackOffset += 2;
			padMask <<= 2;
		} else {
			stackOffset++;
			padMask <<= 1;
		}
	}

	jniArgInfo = returnType << DALVIK_JNI_RETURN_SHIFT;

	if (stackOffset > DALVIK_JNI_COUNT_SHIFT) {
		//too big for "fast" version
		jniArgInfo |= DALVIK_JNI_NO_ARG_INFO;
	} else {
		assert((padFlags & (0xffffffff << DALVIK_JNI_COUNT_SHIFT)) == 0);
		stackOffset -= 2;
		if (stackOffset < 0)
			stackOffset = 0;
		jniArgInfo |= ((stackOffset + 1) / 2) << DALVIK_JNI_COUNT_SHIFT;
		jniArgInfo |= padFlags;
	}

	return jniArgInfo;
}

/*
 * Load information about a static field.
 *
 * This also "prepares" static fields by initializing them
 * to their "standard default values".
 */
static void loadSFieldFromDex(ClassObject* clazz, const DexField* pDexSField,
		StaticField* sfield) {
	DexFile* pDexFile = clazz->pDvmDex->pDexFile;
	const DexFieldId* pFieldId;

	pFieldId = dexGetFieldId(pDexFile, pDexSField->fieldIdx);

	sfield->field.clazz = clazz;
	sfield->field.name = dexStringById(pDexFile, pFieldId->nameIdx);
	sfield->field.signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
	sfield->field.accessFlags = pDexSField->accessFlags;

	/*
	 * Static object field values are set to "standard default values"
	 * (null or 0) until the class is initialized. We delay loading
	 * constant values from the class until that time.
	 */assert(sfield->value.j == 0LL);//cleared earlier with calloc
	//some code maybe here
}

/*
 * Load information about an instance field.
 */
static void loadIFieldFromDex(ClassObject* clazz, const DexField* pDexIField,
		InstField* ifield) {
	DexFile* pDexFile = clazz->pDvmDex->pDexFile;
	const DexFieldId* pFieldId;

	pFieldId = dexGetFieldId(pDexFile, pDexIField->fieldIdx);

	ifield->field.clazz = clazz;
	ifield->field.name = dexStringById(pDexFile, pFieldId->nameIdx);
	ifield->field.signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
	ifield->field.accessFlags = pDexIField->accessFlags;
}

/*
 * Cache java.lang.ref.Reference fields and methods.
 */
static bool precacheReferenceOffsets(ClassObject* clazz) {
	Method* meth;
	int i;

	/*
	 * We trick the GC object scanner by not counting
	 * java.lang.ref.Reference.referent as an object
	 * field. It will get explicitly scanned as part
	 * of the reference-walking process.
	 *
	 * Find the object field named "referent" and put it
	 * just after the list of object reference fields.
	 */
	dvmLinearReadWrite(clazz->classLoader, clazz->ifields);
	for (i = 0; i < clazz->ifieldRefCount; i++) {
		InstField* pField = &clazz->ifields[i];
		if (strcmp(pField->field.name, "referent") == 0) {
			int targetIndex;

			/*
			 * Swap this field with the last object field.
			 */
			targetIndex = clazz->ifieldRefCount - 1;
			if (i != targetIndex) {
				InstField* swapField = &clazz->ifields[targetIndex];
				InstField tmpField;
				int tmpByteOffset;

				/*
				 * It's not currently strictly necessary
				 * for the fields to be in byteOffset order,
				 * but it's more predictable that way.
				 */
				tmpByteOffset = swapField->byteOffset;
				swapField->byteOffset = pField->byteOffset;
				pField->byteOffset = tmpByteOffset;

				tmpField = *swapField;
				*swapField = *pField;
				*pField = tmpField;
			}
			/*
			 * One fewer object field (wink wink).
			 */
			clazz->ifieldRefCount--;
			i--;//don't trip "didn't find it" test if field was last
			break;
		}
	}
	dvmLinearReadOnly(clazz->classLoader, clazz->ifields);
	if (i == clazz->ifieldRefCount) {
		return false;
	}

	/*
	 * Cache pretty much everything about Reference so that
	 * we don't need to call interpreted code when clearing/enqueueing
	 * references. This is fragile, so we'll be paranoid.
	 */
	gDvm.classJavaLangRefReference = clazz;

	gDvm.offJavaLangRefReference_referent = dvmFindFieldOffset(
			gDvm.classJavaLangRefReference, "referent", "Ljava/lang/Object;");
	assert(gDvm.offJavaLangRefReference_referent>=0);

	gDvm.offJavaLangRefReference_queue = dvmFindFieldOffset(
			gDvm.classJavaLangRefReference, "queue",
			"Ljava/lang/ref/ReferenceQueue;");
	assert(gDvm.offJavaLangRefReference_queue>=0);

	gDvm.offJavaLangRefReference_queueNext = dvmFindFieldOffset(
			gDvm.classJavaLangRefReference, "queueNext",
			"Ljava/lang/ref/Reference;");
	assert(gDvm.offJavaLangRefReference_queueNext >= 0);

	gDvm.offJavaLangRefReference_vmData = dvmFindFieldOffset(
			gDvm.classJavaLangRefReference, "vmData", "I");
	assert(gDvm.offJavaLangRefReference_vmData >= 0);

	//enqueueInternal() is private and thus a direct method.
	meth = dvmFindDirectMethodByDescriptor(clazz, "enqueueInternal", "()Z");
	assert(meth!=NULL);
	gDvm.methJavaLangRefReference_enqueueInternal = meth;
	return true;
}

/*
 * Link (prepare and resolve). Verification is deferred until later.
 *
 * This converts symbolic references into pointers. It's independent of
 * the source file format.
 *
 * If "classesResolved" is false, we assume that superclassIdx and
 * interfaces[] are holding class reference indices rather than pointers.
 * The class references will be resolved during link. (This is done when
 * loading from DEX to avoid having to create additional storage to pass
 * the indices around.)
 *
 * Returns "false" with an exception pending on failure.
 */bool dvmLinkClass(ClassObject* clazz, bool classesResolved) {
	u4 superclassIdx = 0;
	bool okay = false;
	bool resolve_okay;
	int numInterfacesResolved = 0;
	int i;

	if (gDvm.verboseClass) {
		//print some information
	}

	/*
	 * "Resolve" the class.
	 *
	 * At this point, clazz's reference fields contain Dex
	 * file indices instead of direct object references.
	 * We need to translate those indices into real references,
	 * while making sure that the GC doesn't sweep any of
	 * the referenced objects.
	 *
	 * The GC will avoid scanning this object as long as
	 * clazz->obj.clazz is gDvm.unlinkedJavaLangClass.
	 * Once clazz is ready, we'll replace clazz->obj.clazz
	 * with gDvm.classJavaLangClass to let the GC know
	 * to look at it.
	 */assert(clazz->obj.clazz == gDvm.unlinkedJavaLangClass);

	/*
	 * It's important that we take care of java.lang.Class
	 * first. If we were to do this after looking up the
	 * superclass (below), Class wouldn't be ready when
	 * java.lang.Object needed it.
	 *
	 * Note that we don't set clazz->obj.clazz yet.
	 */
	if (gDvm.classJavaLangClass == NULL) {
		if (clazz->classLoader == NULL && strcmp(clazz->descriptor,
				"Ljava/lang/Class;") == 0) {
			gDvm.classJavaLangClass = clazz;
		} else {
			gDvm.classJavaLangClass = dvmFindSystemClassNoInit(
					"Ljava/lang/Class;");
			if (gDvm.classJavaLangClass == NULL) {
				//should have thrown one
				assert(dvmCheckException(dvmThreadSelf()));
				goto bail;
			}
		}
	}
	assert(gDvm.classJavaLangClass != NULL);

	/*
	 * Resolve all Dex indices so we can hand the ClassObject
	 * over to the GC. If we fail at any point, we need to remove
	 * any tracked references to avoid leaking memory.
	 */

	/*
	 * All classes have a direct superclass, except for java/lang/Object
	 */
	if (!classesResolved) {
		superclassIdx = (u4) clazz->super; //unpack temp store
		clazz->super = NULL;
	}
	if (strcmp(clazz->descriptor, "Ljava/lang/Object;") == 0) {
		assert(!classesResolved);
		if (superclassIdx != kDexNoIndex) {
			/*
			 * TODO: is this invariant true for all java/lang/Objects,
			 * regardless of the class loader? For now, assume it is.
			 */
			dvmThrowException("Ljava/lang/ClassFormatError;",
					"java.lang.Object has a superclass");
			goto bail;
		}

		/*
		 * Don't finalize objects whose classes use the
		 * default (empty) Object.finalize().
		 */CLEAR_CLASS_FLAG(clazz,CLASS_ISFINALIZABLE);
	} else {
		if (!classesResolved) {
			if (superclassIdx == kDexNoIndex) {
				dvmThrowException("Ljava/lang/LinkageError;",
						"no superclass defined");
				goto bail;
			}
			clazz->super = dvmResolveClass(clazz, superclassIdx, false);
			if (clazz->super == NULL) {
				assert(dvmCheckException(dvmThreadSelf()));
				if (gDvm.optimizing) {
					//happens with "external" libs
					//printf some information.
				} else {
					//printf some information.
				}
				goto bail;
			}
		}

		//verify
		if (dvmIsFinalClass(clazz->super)) {
			dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
					"superclass is final");
			goto bail;
		} else if (dvmIsInterfaceClass(clazz->super)) {
			dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
					"super class is an interface");
			goto bail;
		} else if (!dvmCheckClassAccess(clazz, clazz->super)) {
			dvmThrowException("Ljava/lang/IllegalAccessError;",
					"superclass not accessible");
			goto bail;
		}

		/*
		 * Don't let the GC reclaim the superclass.
		 * TODO: shouldn't be needed; remove when things stabilize
		 */
		dvmAddTrackedAlloc((Object*) clazz->super, NULL);

		/*
		 * Inherit finalizability from the superclass. If this
		 * class also overrides finalize(), its CLASS_ISFINALIZABLE
		 * bit will already be set.
		 */
		if (IS_CLASS_FLAG_SET(clazz->super,CLASS_ISFINALIZABLE)) {
			SET_CLASS_FLAG(clazz,CLASS_ISFINALIZABLE);
		}

		/*
		 * See if this class descends from java.lang.Reference
		 * and set the class flags appropriately.
		 */
		if (IS_CLASS_FLAG_SET(clazz->super,CLASS_ISREFERENCE)) {
			u4 superRefFlags;

			/*
			 * We've already determined the reference type of this
			 * inheritance chain. Inherit reference-ness from the superclass.
			 */
			superRefFlags
					=GET_CLASS_FLAG_GROUP(clazz->super,
							CLASS_ISREFERENCE|CLASS_ISWEAKREFERENCE|CLASS_ISPHANTOMREFERENCE);
			SET_CLASS_FLAG(clazz,superRefFlags);
		} else if (clazz->classLoader == NULL && clazz->super->classLoader
				==NULL && strcmp(clazz->super->descriptor,
				"Ljava/lang/ref/Reference;") == 0) {
			u4 refFlags;

			/*
			 * This class extends Reference, which means it should
			 * be one of the magic Soft/Weak/PhantomReference classes.
			 */
			refFlags = CLASS_ISREFERENCE;
			if (strcmp(clazz->descriptor, "Ljava/lang/ref/SoftReference;") == 0) {
				//Only CLASS_ISREFERENCE is set for soft references.
			} else if (strcmp(clazz->descriptor,
					"Ljava/lang/ref/WeakReference;") == 0) {
				refFlags |= CLASS_ISWEAKREFERENCE;
			} else if (strcmp(clazz->descriptor,
					"Ljava/lang/ref/PhantomReference;") == 0) {
				refFlags |= CLASS_ISPHANTOMREFERENCE;
			} else {
				/*
				 * No-one else is allowed to inherit directly
				 * from Reference.
				 */
				//xxx is this the right exception? better than an assertion.
				dvmThrowException("Ljava/lang/LinkageError;",
						"illegal inheritance from Reference");
				goto bail;
			}

			/*
			 * The class should not have any reference bits set yet.
			 */assert(GET_CLASS_FLAG_GROUP(clazz,CLASS_ISREFERENCE|CLASS_ISWEAKREFERENCE|CLASS_ISPHANTOMREFERENCE));
			SET_CLASS_FLAG(clazz,refFlags);
		}
	}

	if (!classesResolved && clazz->interfaceCount > 0) {
		/*
		 * Resolve the interfaces implemented directly by this class. We
		 * stuffed the class index into the interface pointer slot.
		 */
		dvmLinearReadWrite(clazz->classLoader, clazz->interfaces);
		for (i = 0; i < clazz->interfaceCount; i++) {
			u4 interfaceIdx;

			interfaceIdx = (u4) clazz->interfaces[i];//unpack temp store
			assert(interfaceIdx!=kDexNoIndex);
			clazz->interfaces[i] = dvmResolveClass(clazz, interfaceIdx, false);
			if (clazz->interfaces[i] == NULL) {
				const DexFile* pDexFile = clazz->pDvmDex->pDexFile;
				assert(dvmCheckException(dvmThreadSelf()));
				dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);

				const char* classDescriptor;
				classDescriptor = dexStringByTypeIdx(pDexFile, interfaceIdx);
				if (gDvm.optimizing) {
					//print some information.
				} else {
					//print some information.
				}
				goto bail_during_resolve;
			}

			//are we allowed to implements this interface?
			if (!dvmCheckClassAccess(clazz, clazz->interfaces[i])) {
				dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
				dvmThrowException("Ljava/lang/IllegalAccessError;",
						"interface not accessible");
				goto bail_during_resolve;
			}

			/*
			 * Don't let the GC reclaim the interface class.
			 * TODO: shouldn't be needed; remove when things stabilize
			 */
			dvmAddTrackedAlloc((Object*) clazz->interfaces[i], NULL);

			numInterfacesResolved++;
		}
		dvmLinearReadOnly(clazz->classLoader, clazz->interfaces);
	}

	/*
	 * The ClassObject is now in a GC-able state. We let the GC
	 * realize this by punching in the real class type, which is
	 * always java.lang.Class.
	 *
	 * After this line, clazz will be fair game for the GC.
	 * Every field that the GC will look at must now be valid:
	 * - clazz->super
	 * - clazz->classLoader
	 * - clazz->sfields
	 * - clazz->interfaces
	 */
	clazz->obj.clazz = gDvm.classJavaLangClass;

	if (false) {
		bail_during_resolve: resolve_okay = false;
	} else {
		resolve_okay = true;
	}

	/*
	 * Now that the GC can scan the ClassObject, we can let
	 * go of the explicit references we were holding onto.
	 *
	 * Either that or we failed, in which case we need to
	 * release the references so we don't leak memory.
	 */
	if (clazz->super != NULL) {
		dvmReleaseTrackedAlloc((Object*) clazz->super, NULL);
	}
	for (i = 0; i < numInterfacesResolved; i++) {
		dvmReleaseTrackedAlloc((Object*) clazz->interfaces[i], NULL);
	}

	if (!resolve_okay) {
		goto bail;
	}

	/*
	 * Populate vtable
	 */
	if (dvmIsInterfaceClass(clazz)) {
		//no vtable; just set the method indices
		int count = clazz->virtualMethodCount;

		if (count != (u2) count) {
			goto bail;
		}

		dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);

		for (i = 0; i < count; i++)
			clazz->virtualMethods[i].methodIndex = (u2) i;

		dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
	} else {
		if (!createVtable(clazz)) {
			goto bail;
		}
	}

	/*
	 * Populate interface method tables. Can alter the vtable.
	 */
	if (!createIftable(clazz))
		goto bail;

	/*
	 * Insert special-purpose "stub" method implementations.
	 */
	if (!insertMethodStubs(clazz))
		goto bail;

	/*
	 * Compute instance field offsets and, hence, the size of the object.
	 */
	if (!computeFieldOffsets(clazz))
		goto bail;

	/*
	 * Cache fields and methods from java/lang/ref/Reference and
	 * java/lang/Class. This has to happen after computeFieldOffsets().
	 */
	if (clazz->classLoader == NULL) {
		if (strcmp(clazz->descriptor, "Ljava/lang/ref/Reference;") == 0) {
			if (!precacheReferenceOffsets(clazz)) {
				dvmThrowException("Ljava/lang/InternalError;", NULL);
				goto bail;
			}
		} else if (clazz == gDvm.classJavaLangClass) {
			gDvm.offJavaLangClass_pd = dvmFindFieldOffset(clazz, "pd",
					"Ljava/security/ProtectionDomain;");
			if (gDvm.offJavaLangClass_pd <= 0) {
				dvmAbort();//we're not going to get much farther.
			}
		}
	}

	/*
	 * Done!
	 */
	if (IS_CLASS_FLAG_SET(clazz,CLASS_ISPREVERIFIED))
		clazz->status = CLASS_VERIFIED;
	else
		clazz->status = CLASS_RESOLVED;
	okay = true;
	if (gDvm.verboseClass) {
		//printf some information.
	}

	/*
	 * We send CLASS_PREPARE events to the debugger from here. The
	 * definition of "preparation" is creating the static fields for a
	 * class and initializing them to the standard default values, but not
	 * executing any code (that comes later, during "initialization").
	 *
	 * We did the static prep in loadSFieldFromDex() while loading the class.
	 *
	 * The class has been prepared and resolved but possibly not yet verified
	 * at this point.
	 */
	if (gDvm.debuggerActive) {
		dvmDbgPostClassPrepare(clazz);
	}

	bail: if (!okay) {
		clazz->status = CLASS_ERROR;
		if (!dvmCheckException(dvmThreadSelf())) {
			dvmThrowException("Ljava/lang/VirtualMachineError;", NULL);
		}
	}
	return okay;
}

/*
 * Create the virtual method table.
 *
 * The top part of the table is a copy of the table from our superclass,
 * with our local methods overriding theirs. The bottom part of the table
 * has any new methods we defined.
 */
static bool createVtable(ClassObject* clazz) {
	bool result = false;
	int maxCount;
	int i;

	if (clazz->super != NULL) {
	}

	//the virtual methods we define, plus the superclass vtable size
	maxCount = clazz->virtualMethodCount;
	if (clazz->super != NULL) {
		maxCount += clazz->super->vtableCount;
	} else {
		/*
		 * TODO: is this invariant true for all java/lang/Objects,
		 * regardless of the class loader? For now, assume it is.
		 */assert(strcmp(clazz->descriptor,"Ljava/lang/Object;")==0);
	}

	/*
	 * Over-allocate the table, then realloc it down if necessary. So
	 * long as we don't allocate anything in between we won't cause
	 * fragmentation, and reducing the size should be unlikely to cause
	 * a buffer copy.
	 */
	dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
	clazz->vtable = (Method**) dvmLinearAlloc(clazz->classLoader,
			sizeof(Method*) * maxCount);
	if (clazz->vtable == NULL)
		goto bail;

	if (clazz->super != NULL) {
		int actualCount;

		memcpy(clazz->vtable,clazz->super->vtable,
				sizeof(*(clazz->vtable))*clazz->super->vtableCount);
		actualCount = clazz->super->vtableCount;

		/*
		 * See if any of our virtual methods override the superclass.
		 */
		for (i = 0; i < clazz->virtualMethodCount; i++) {
			Method* localMeth = &clazz->virtualMethods[i];
			int si;

			for (si = 0; si < clazz->super->vtableCount; si++) {
				Method* superMeth = clazz->vtable[si];

				if (dvmCompareMethodNamesAndProtos(localMeth, superMeth) == 0) {
					//verify
					if (dvmIsFinalMethod(superMeth)) {
						goto bail;
					}
					clazz->vtable[si] = localMeth;
					localMeth->methodIndex = (u2) si;
					break;
				}
			}

			if (si == clazz->super->vtableCount) {
				//not an override, add to end
				clazz->vtable[actualCount] = localMeth;
				localMeth->methodIndex = (u2) actualCount;
				actualCount++;
			}
		}

		if (actualCount != (u2) actualCount) {
			goto bail;
		}

		assert(actualCount<=maxCount);

		if (actualCount < maxCount) {
			assert(clazz->vtable!=NULL);
			dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
			clazz->vtable = dvmLinearRealloc(clazz->classLoader, clazz->vtable,
					sizeof(*(clazz->vtable)) * actualCount);
			if (clazz->vtable == NULL) {
				goto bail;
			} else {
			}
		}

		clazz->vtableCount = actualCount;
	} else {
		//java/lang/Object case
		int count = clazz->virtualMethodCount;
		if (count != (u2) count) {
			goto bail;
		}

		for (i = 0; i < count; i++) {
			clazz->vtable[i] = &clazz->virtualMethods[i];
			clazz->virtualMethods[i].methodIndex = (u2) i;
		}
		clazz->vtableCount = clazz->virtualMethodCount;
	}
	result = true;
	bail: dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
	dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
	return result;
}

/*
 * Create and populate "iftable"
 *
 * The set of interfaces we support is the combination of the interfaces
 * we implement directly and those implemented by our superclass. Each
 * interface can have one or more "superinterfaces", which we must also
 * support. For speed we flatten the tree out.
 *
 * We might be able to speed this up when there are lots of interfaces
 * by merge-sorting the class pointers and binary-searching when removing
 * duplicates. We could also drop the duplicate removal -- it's only
 * there to reduce the memory footprint.
 *
 * Because of "Miranda methods", this may reallocate clazz->virtualMethods.
 *
 * Returns "true" on success.
 */
static bool createIftable(ClassObject* clazz) {
	bool result = false;
	bool zapIftable = false;
	bool zapVtable = false;
	bool zapIfvipool = false;
	int ifCount, superIfCount, idx;
	int i;

	if (clazz->super != NULL)
		superIfCount = clazz->super->iftableCount;
	else
		superIfCount = 0;

	ifCount = superIfCount;
	ifCount += clazz->interfaceCount;
	for (i = 0; i < clazz->interfaceCount; i++)
		ifCount += clazz->interfaces[i]->iftableCount;

	if (ifCount == 0) {
		assert(clazz->iftableCount==0);
		assert(clazz->iftable==NULL);
		result = true;
		goto bail;
	}

	/*
	 * Create a table with enough space for all interfaces, and copy the
	 * superclass' table in.
	 */
	clazz->iftable = (InterfaceEntry*) dvmLinearAlloc(clazz->classLoader,
			sizeof(InterfaceEntry) * ifCount);
	zapIftable = true;
	memset(clazz->iftable,0x00,sizeof(InterfaceEntry)*ifCount);
	if (superIfCount != 0) {
		memcpy(clazz->iftable,clazz->super->iftable,
				sizeof(InterfaceEntry)*superIfCount);
	}

	/*
	 * Create a flattened interface hierarchy of our immediate interfaces.
	 */
	idx = superIfCount;

	for (i = 0; i < clazz->interfaceCount; i++) {
		ClassObject* interf;
		int j;

		interf = clazz->interfaces[i];
		assert(interf!=NULL);

		//make sure this is still an interface class
		if (!dvmIsInterfaceClass(interf)) {
			dvmThrowExceptionWithClassMessage(
					"Ljava/lang/IncompatibleClassChangeError",
					clazz->descriptor);
			goto bail;
		}

		//add entry for this interface
		clazz->iftable[idx++].clazz = interf;

		//add entries for the interface's superinterfaces
		for (j = 0; j < interf->iftableCount; j++) {
			clazz->iftable[idx++].clazz = interf->iftable[j].clazz;
		}
	}

	assert(idx==ifCount);

	/*
	 * Remove anything redundant from our recent additions. Note we have
	 * to traverse the recent adds when looking for duplicates...
	 */
	//some code here.

	clazz->iftableCount = ifCount;

	/*
	 * If we're an interface, we don't need the vtable pointers, so
	 * we're done. If this class doesn't implement an interface that
	 * out superclass doesn't have, then we again have nothing to do.
	 */
	if (dvmIsInterfaceClass(clazz) || superIfCount == ifCount) {
		result = true;
		goto bail;
	}

	/*
	 * When we're handling invokeinterface, we probably have an object
	 * whose type is an interface class rather than a concrete class. We
	 * need to convert the method reference into a vtable index. So,for
	 * every entry in "iftable", we create a list of vtable indices.
	 *
	 * Because our table encompasses the superclass vtable, we can use
	 * the vtable indices from our superclass for all of the interfaces
	 * that weren't directly implemented by us.
	 *
	 * Each entry in "iftable" has a pointer to the start of its set of
	 * vtable offsets. The iftable entries in the superclass point to
	 * storage allocated in the superclass, and the iftable entries added
	 * for this class point to storage allocated in this class. ...
	 */
	int poolSize = 0;
	for (i = superIfCount; i < ifCount; i++) {
		/*
		 * Note it's valid for an interface to have no methods (e.g.
		 * java/io/Serializable).
		 */
		poolSize += clazz->iftable[i].clazz->virtualMethodCount;
	}

	if (poolSize == 0) {
		result = true;
		goto bail;
	}

	clazz->ifviPoolCount = poolSize;
	clazz->ifviPool = (int*) dvmLinearAlloc(clazz->classLoader,
			poolSize * sizeof(int*));
	zapIfvipool = true;

	/*
	 * Fill in the vtable offsets for the interfaces that weren't part of
	 * our superclass.
	 */
	int poolOffset = 0;
	Method** mirandaList = NULL;
	int mirandaCount = 0, mirandaAlloc = 0;

	for (i = superIfCount; i < ifCount; i++) {
		ClassObject* interface;
		int methIdx;

		clazz->iftable[i].methodIndexArray = clazz->ifviPool + poolOffset;
		interface = clazz->iftable[i].clazz;
		poolOffset += interface->virtualMethodCount;//end here

		/*
		 * For each method listed in the interface's method list, find the
		 * matching method in our class's method list. We want to favor the
		 * subclass over the superclass, which just requires walking
		 * back from the end of the vtable. (This only matters if the
		 * superclass defines a private method and this class redefines
		 * it -- otherwise it would use the same vtable slot. In Dalvik
		 * those don't end up in the virtual method table, so it shouldn't
		 * matter which direction we go. We walk it backward anyway.)
		 *
		 * Suppose we have the following arrangement:
		 *  public interface MyInterface
		 *    public boolean inInterface();
		 *  public abstract class MirandaAbstract implements MirandaInterface
		 *    //public abstract boolean inInterface(); //not declared!
		 *    public boolean inAbstract(){ stuff } //in vtable
		 *  public class MirandClass extends MirandaAbstract
		 *    public boolean inInterface() {stuff}
		 *    public boolean inAbstract() {stuff} //in vtable
		 *
		 *  The javac compiler happily compiles MirandaAbstract even though
		 *  it doesn't declare all methods from its interface. When we try
		 *  to set up a vtable for MirandaAbstract, we find that we don't
		 *  have an slot for inInterface. To prevent this, we synthesize
		 *  abstract method declarations in MirandaAbstract.
		 *
		 *  We have to expand vtable and update some things that point at it,
		 *  so we accumulate the method list and do it all at once below.
		 */
		for (methIdx = 0; methIdx < interface->virtualMethodCount; methIdx++) {
			Method* imeth = &interface->virtualMethods[methIdx];
			int j;

			for (j = clazz->vtableCount - 1; j >= 0; j--) {
				if (dvmCompareMethodNamesAndProtos(imeth, clazz->vtable[j])
						== 0) {
					clazz->iftable[i].methodIndexArray[methIdx] = j;
					break;
				}
			}
			if (j < 0) {
				if (mirandaCount == mirandaAlloc) {
					mirandaAlloc += 8;
					if (mirandaList == NULL) {
						mirandaList = dvmLinearAlloc(clazz->classLoader,
								mirandaAlloc * sizeof(Method*));
					} else {
						dvmLinearReadOnly(clazz->classLoader, mirandaList);
						mirandaList = dvmLinearRealloc(clazz->classLoader,
								mirandaList, mirandaAlloc * sizeof(Method*));
					}
					assert(mirandaList!=NULL); //mem failed + we leaked
				}

				/*
				 * These may be redundant (e.g. method with same name and
				 * signature declared in two interfaces implemented by the
				 * same abstract class). We can squeeze the duplicates
				 * out here.
				 */
				int mir;
				for (mir = 0; mir < mirandaCount; mir++) {
					if (dvmCompareMethodNamesAndProtos(mirandaList[mir], imeth)) {
						break;
					}
				}

				//point the iftable at a phantom slot index
				clazz->iftable[i].methodIndexArray[methIdx]
						= clazz->vtableCount + mir;

				//if non-duplicate among Mirandas, add to Miranda list
				if (mir == mirandaCount) {
					mirandaList[mirandaCount++] = imeth;
				}
			}
		}
	}

	if (mirandaCount != 0) {
		Method* newVirtualMethods;
		Method* meth;
		int oldMethodCount, oldVtableCount;

		for (i = 0; i < mirandaCount; i++) {
			//printf some information
		}

		/*
		 * We found methods in one or more interfaces for which we do not
		 * have vtable entries. We have to expand our virtualMethods
		 * table (which might be empty) to hold some new entries.
		 */
		if (clazz->virtualMethods == NULL) {
			newVirtualMethods
					= (Method*) dvmLinearAlloc(
							clazz->classLoader,
							sizeof(Method) * (clazz->virtualMethodCount
									+ mirandaCount));
		} else {
			newVirtualMethods
					= (Method*) dvmLinearRealloc(
							clazz->classLoader,
							clazz->virtualMethods,
							sizeof(Method) * (clazz->virtualMethodCount
									+ mirandaCount));
		}
		if (newVirtualMethods != clazz->virtualMethods) {
			/*
			 * Table was moved in memory. We have to run through the
			 * vtable and fix the pointers. The vtable entries might be
			 * pointing at superclasses, so we flip it around: run through
			 * ...
			 */
			dvmLinearReadWrite(clazz->classLoader, clazz->vtable);
			Method* meth = newVirtualMethods;
			for (i = 0; i < clazz->virtualMethodCount; i++, meth++)
				clazz->vtable[meth->methodIndex] = meth;
			dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
		}

		oldMethodCount = clazz->virtualMethodCount;
		clazz->virtualMethods = newVirtualMethods;
		clazz->virtualMethodCount += mirandaCount;

		dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);

		/*
		 * We also have to expand the vtable.
		 */assert(clazz->vtable!=NULL);
		clazz->vtable = (Method**) dvmLinearRealloc(clazz->classLoader,
				clazz->vtable,
				sizeof(Method*) * (clazz->vtableCount + mirandaCount));
		if (clazz->vtable == NULL) {
			assert(false);
			goto bail;
		}
		zapVtable = true;

		oldVtableCount = clazz->vtableCount;
		clazz->vtableCount += mirandaCount;

		/*
		 * Now we need to create the fake methods. We clone the abstract
		 * method definition from the interface and then replace a few
		 * things.
		 */
		meth = clazz->virtualMethods + oldMethodCount;
		for (i = 0; i < mirandaCount; i++, meth++) {
			dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
			cloneMethod(meth, mirandaList[i]);
			meth->clazz = clazz;
			meth->accessFlags |= ACC_MIRANDA;
			meth->methodIndex = (u2) (oldVtableCount + i);
			dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);

			//point the new vtable entry at the new method
			clazz->vtable[oldVtableCount + i] = meth;
		}

		dvmLinearReadOnly(clazz->classLoader, mirandaList);
		dvmLinearFree(clazz->classLoader, mirandaList);
	}

	/*
	 * TODO?
	 */
	result = true;
	bail: if (zapIftable)
		dvmLinearReadOnly(clazz->classLoader, clazz->iftable);
	if (zapVtable)
		dvmLinearReadOnly(clazz->classLoader, clazz->vtable);
	if (zapIfvipool)
		dvmLinearReadOnly(clazz->classLoader, clazz->ifviPool);
	return result;
}

/*
 * Provide "stub" implementations for methods without them.
 *
 * Currently we provide an implementation for all abstract methods that
 * throws an AbstractMethodError exception. This allows us to avoid an
 * explicit check for abstract methods in every virtual call.
 */
static bool insertMethodStubs(ClassObject* clazz) {
	dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);

	Method* meth;
	int i;

	meth = clazz->virtualMethods;
	for (i = 0; i < clazz->virtualMethodCount; i++, meth++) {
		if (dvmIsAbstractMethod(meth)) {
			assert(meth->insns==NULL);
			assert(meth->nativeFunc==NULL||meth->nativeFunc==(DalvikBridgeFunc)dvmAbstractMethodStub);
			meth->accessFlags |= ACC_NATIVE;
			meth->nativeFunc = (DalvikBridgeFunc) dvmAbstractMethodStub;
		}
	}

	dvmLinearReadOnly(clazz->classLoader, clazz->virtualMethods);
	return true;
}

/*
 * Swap two instance fields.
 */
static inline void swapField(InstField* pOne, InstField* pTwo) {
	InstField swap;

	swap = *pOne;
	*pOne = *pTwo;
	*pTwo = swap;
}

/*
 * Assign instance fields to u4 slots.
 *
 * The top portion of the instance field area is occupied by the superclass
 * fields, the bottom by the fields for this class.
 *
 * "long" and "double" fields occupy two adjacent slots. On some
 * architectures, 64-bit quantities must be 64-bit aligned, so we need to
 * arrange fields (or introduce padding) to ensure this. We assume the
 * fields of the topmost superclass (i.e. Object)
 */
static bool computeFieldOffsets(ClassObject* clazz) {
	int fieldOffset;
	int i, j;

	dvmLinearReadWrite(clazz->classLoader, clazz->ifields);

	if (clazz->super != NULL)
		fieldOffset = clazz->super->objectSize;
	else
		fieldOffset = offsetof(DataObject,instanceData);

	/*
	 * Start by moving all reference fields to the front.
	 */
	clazz->ifieldRefCount = 0;
	j = clazz->ifieldCount - 1;
	for (i = 0; i < clazz->ifieldCount; i++) {
		InstField* pField = &clazz->ifields[i];
		char c = pField->field.signature[0];

		if (c != '[' && c != 'L') {
			/*
			 * This isn't a reference field; see if any reference fields
			 * follow this one. If so, we'll move it to this position.
			 * (quicksort-style partitioning)
			 */
			while (j > i) {
				InstField* refField = &clazz->ifields[j--];
				char rc = refField->field.signature[0];

				if (rc == '[' || rc == 'L') {
					/*
					 * Here's a reference field that follows at least one
					 * non-reference field. Swap it with the current field.
					 * (When this returns,"pField" points to the reference
					 * field, and "refField" points to the non-ref field.)
					 */
					swapField(pField, refField);

					/*
					 * Fix the signature.
					 */
					c = rc;

					clazz->ifieldRefCount++;
					break;
				}
			}
		} else {
			//This is a reference field.
			clazz->ifieldRefCount++;
		}

		/*
		 * If we've hit the end of the reference fields,break.
		 */
		if (c != '[' && c != 'L')
			break;

		pField->byteOffset = fieldOffset;
		fieldOffset += sizeof(u4);
	}

	/*
	 * Now we want to pack all of the double-wide fields together. If we're
	 * not aligned, though, we want to shuffle one 32-bit field into place.
	 * If we can't find one, we'll have to pad it.
	 */
	if (i != clazz->ifieldCount && (fieldOffset & 0x04) != 0) {
		InstField* pField = &clazz->ifields[i];
		char c = pField->field.signature[0];

		if (c != 'J' && c != 'D') {
			/*
			 * The field that comes next is 32-bit, so just advance past it.
			 */
			pField->byteOffset = fieldOffset;
			fieldOffset += sizeof(u4);
			i++;
		} else {
			/*
			 * Next field is 64-bit, so search for a 32-bit field we can
			 * swap into it.
			 */bool found = false;
			j = clazz->ifieldCount - 1;
			while (j > i) {
				InstField* singleField = &clazz->ifields[j--];
				char rc = singleField->field.signature[0];

				if (rc != 'J' && rc != 'D') {
					swapField(pField, singleField);
					pField->byteOffset = fieldOffset;
					fieldOffset += sizeof(u4);
					found = true;
					i++;
					break;
				}
			}
			if (!found) {
				fieldOffset += sizeof(u4);
			}
		}
	}

	/*
	 * Alignment is good, shuffle any double-wide fields forward, and
	 * finish assigning field offsets to all fields.
	 */assert(i==clazz->ifieldCount||(fieldOffset&0x04)==0);
	j = clazz->ifieldCount - 1;
	for (; i < clazz->ifieldCount; i++) {
		InstField* pField = &clazz->ifields[i];
		char c = pField->field.signature[0];

		if (c != 'D' && c != 'J') {
			/*
			 * This isn't a double-wide field; see if any double fields
			 * follow this one. If so, we'll move it to this position.
			 * (quicksort-style partitioning)
			 */
			while (j > i) {
				InstField* doubleField = &clazz->ifields[j--];
				char rc = doubleField->field.signature[0];

				if (rc == 'D' || rc == 'J') {
					/*
					 * Here's a double-wide field that follows at least one
					 * non-double field. Swap it with the current field.
					 * (When this returns, "pField" points to the reference
					 * field, and "doubleField" points to the non-double field.)
					 */
					swapField(pField, doubleField);
					c = rc;

					break;
				}
			}
		} else {
			//This is a double-wide field, leave it be.
		}
		pField->byteOffset = fieldOffset;
		fieldOffset += sizeof(u4);
		if (c == 'J' || c == 'D')
			fieldOffset += sizeof(u4);
	}

	/*
	 * We map a C struct directly on top of java/lang/Class objects. Make
	 * sure we left enough room for the instance fields.
	 */assert(clazz!=gDvm.classJavaLangClass||(size_t)fieldOffset<offsetof(ClassObject,instanceData)+sizeof(clazz->instanceData));

	clazz->objectSize = fieldOffset;

	dvmLinearReadOnly(clazz->classLoader, clazz->ifields);
	return true;
}

/*
 * The class failed to initialize on a previous attempt, so we want ti throw
 * a NoClassDefFoundError (v2 2.17.5). The exception to this rule is if we
 * failed in verification, in which case v2 5.4.1 says we need to re-throw
 * the previous error.
 */
static void throwEarlierClassFailure(ClassObject* clazz) {
	if (clazz->verifyErrorClass == NULL) {
		dvmThrowExceptionWithClassMessage("Ljava/lang/NoClassDefFoundError;",
				clazz->descriptor);
	} else {
		dvmThrowExceptionByClassWithClassMessage(clazz->verifyErrorClass,
				clazz->descriptor);
	}
}

/*
 * Free anything in a ClassObject that was allocated on the system heap.
 *
 * The ClassObject itself is allocated on the GC heap, so we leave it for
 * the garbage collector.
 *
 * NOTE: this may be called with a partially-constructed object.
 * NOTE: there is no particular ordering imposed, so don't go poking
 * at superclasses.
 */
void dvmFreeClassInnards(ClassObject* clazz) {

}

/*
 * If a class has not been initialized, do so by executing the code in
 * <clinit>. The sequence is describe in the VM spec v2 2.17.5
 *
 * It is possible for multiple threads to arrive here simultaneously, so
 * we need to lock the class while we check stuff. We know that no
 * interpreted code has access to the class yet, so we can use the class's
 * monitor lock.
 *
 * We will often be called recursively, e.g. when the <clinit> code resolves
 * one of its fields, the field resolution will try to initialize the class.
 *
 * This can get very interesting if a class has a static field initialized
 * to a new instance of itself. <clinit> will end up calling <init> on
 * the members it is initialize instance fields. This will leave the
 * static-referenced objects in a partially initialized state. This is
 * reasonably rare and can sometimes be cured with proper field ordering.
 *
 * On failure, returns "false" with an exception raised.
 *
 * -----
 *
 *
 */bool dvmInitClass(ClassObject* clazz) {
	Thread* self = dvmThreadSelf();
	const Method* method;

	dvmLockObject(self, (Object*) clazz);
	assert(dvmIsClassLinked(clazz)||clazz->status==CLASS_ERROR);

	/*
	 * If the class hasn't been verified yet, do so now.
	 */
	if (clazz->status < CLASS_VERIFIED) {
		/*
		 * If we're in an "erroneous" state, throw an exception and bail.
		 */
		if (clazz->status == CLASS_ERROR) {
			throwEarlierClassFailure(clazz);
			//some code here.
		}

		assert(clazz->status==CLASS_RESOLVED);

	}
}

 /*
  * Retrieve the system (a/k/a application) class loader.
  */
 Object* dvmGetSystemClassLoader(void) {

 }
/*
 * =====================================================
 * 		Method Prototypes and Descriptors
 * =====================================================
 */
/*
 * Compare the two method names and prototypes, a la strcmp(). The
 * name is considered the "major" order and the prototype the "minor"
 * order. The prototypes are compared as if by dvmCompareMethodProtos()
 */
int dvmCompareMethodNamesAndProtos(const Method* method1, const Method* method2) {
	int result = strcmp(method1->name, method2->name);

	if (result != 0) {
		return result;
	}

	return dvmCompareMethodProtos(method1, method2);
}

/*
 * Compare a (name, method descriptor) pair with the (name, prototype) of
 * a method, a la strcmp(). The name is considered the "major" order and
 * the protype the "minor" order. The descriptor and prototype are
 * compared as if by dvmCompareDescriptorAndMethodProto().
 */
int dvmCompareNameDescriptorAndMethod(const char*name, const char* descriptor,
		const Method* method) {
	int result = strcmp(name, method->name);

	if (result != 0) {
		return result;
	}

	return dvmCompareDescriptorAndMethodProto(descriptor, method);
}
